home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
-
- File : mpega_decode.c
-
- Author : Stéphane TAVENARD
-
- $VER: mpega_decode.c 1.0 (23/06/1995)
-
- (C) Copyright 1995-1995 Stéphane TAVENARD
- All Rights Reserved
-
- #Rev| Date | Comment
- ----|----------|--------------------------------------------------------
- 0 |27/05/1995| Initial revision ST
- 1 |23/06/1995| First release (aminet) ST
-
- ------------------------------------------------------------------------
-
- MPEG Audio decode functions
-
- ------------------------------------------------------------------------------*/
-
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
- #include <stdlib.h>
- #include "AudioPort.h"
- #include "AIFF.h"
- #include "mpega_decode_asm.h"
- #include "mpega_decode.h"
-
- frame_params *MPEGA_close( frame_params *fr_ps )
- {
- if( !fr_ps ) return NULL;
- if( fr_ps->audio_port ) {
- AU_close( fr_ps->audio_port );
- fr_ps->audio_port = NULL;
- }
- if( fr_ps->bs ) BSTR_close( fr_ps->bs );
- fr_ps->bs = NULL;
- if( fr_ps->header ) free( fr_ps->header );
- if( fr_ps->bit_alloc ) free( fr_ps->bit_alloc );
- if( fr_ps->scfsi ) free( fr_ps->scfsi );
- if( fr_ps->scale_index ) free( fr_ps->scale_index );
- if( fr_ps->sample ) free( fr_ps->sample );
- if( fr_ps->fraction ) free( fr_ps->fraction );
- free( fr_ps );
- return NULL;
- }
-
- frame_params *MPEGA_open( void )
- {
- frame_params *fr_ps;
-
- fr_ps = (frame_params *)malloc( sizeof( frame_params ) );
- if( !fr_ps ) return NULL;
- memset( fr_ps, 0, sizeof( frame_params ) );
- fr_ps->header = (layer *)malloc( sizeof( layer ) );
- if( !fr_ps->header ) return MPEGA_close( fr_ps );
- memset( fr_ps->header, 0, sizeof( layer ) );
- fr_ps->bit_alloc = (int *)malloc( sizeof( int ) * 2 * SBLIMIT );
- if( !fr_ps->bit_alloc ) return MPEGA_close( fr_ps );
- fr_ps->scfsi = (int *)malloc( sizeof( int ) * 2 * SBLIMIT );
- if( !fr_ps->scfsi ) return MPEGA_close( fr_ps );
- fr_ps->scale_index = (int *)malloc( sizeof( int ) * 2 * 3 * SBLIMIT );
- if( !fr_ps->scale_index ) return MPEGA_close( fr_ps );
- fr_ps->sample = (int *)malloc( sizeof( int ) * 2 * 3 * SBLIMIT );
- if( !fr_ps->sample ) return MPEGA_close( fr_ps );
- fr_ps->fraction = (INT *)malloc( sizeof( INT ) * 2 * 3 * SBLIMIT );
- if( !fr_ps->fraction ) return MPEGA_close( fr_ps );
-
- /* default values */
- fr_ps->freq_div = 1;
- fr_ps->quality = 2;
- fr_ps->bitstream_buffer_size = BSTR_BUFFER_SIZE;
-
- return fr_ps;
- }
-
- #define OUT_BUFFER_SIZE (13824*4)
-
- static BOOL stereo_file = FALSE;
- static BYTE *l_file_buffer = NULL;
- static BYTE *r_file_buffer = NULL;
- static BYTE *stereo_file_buffer = NULL;
-
- static int init_file( frame_params *fr_ps )
- {
- long buffer_byte_size;
-
- if( !fr_ps->out_file_name ) return 1;
-
- if( !fr_ps->out_file ) {
- if( strcmp( fr_ps->out_file_name, "stdout" ) == 0 ) {
- fr_ps->out_file = stdout;
- }
- else {
- fr_ps->out_file = fopen( fr_ps->out_file_name, "w+b" );
- if( !fr_ps->out_file ) {
- fprintf( stderr, "Can't create file '%s'\n", fr_ps->out_file_name );
- return 0;
- }
- }
- }
- if( fr_ps->out_file_type == MPEGA_FILETYPE_AIFF ) {
- if( AIFF_seek_to_sound_data( fr_ps->out_file ) == -1 ) {
- fclose( fr_ps->out_file );
- fr_ps->out_file = NULL;
- return 0;
- }
- }
-
- fr_ps->out_buffer_size = OUT_BUFFER_SIZE;
-
- if( (fr_ps->stereo > 1) && !(fr_ps->mono_forced) ) stereo_file = TRUE;
- else stereo_file = FALSE;
- if( fr_ps->output_8bits ) buffer_byte_size = fr_ps->out_buffer_size;
- else buffer_byte_size = (fr_ps->out_buffer_size)*2;
- fr_ps->out_buffer[ 0 ] = fr_ps->out_buffer[ 1 ] = NULL;
- fr_ps->out_buffer[ 0 ] = (BYTE *)malloc( buffer_byte_size );
- if( !fr_ps->out_buffer[ 0 ] ) exit( 0 );
- if( stereo_file ) {
- fr_ps->out_buffer[ 1 ] = (BYTE *)malloc( buffer_byte_size );
- if( !fr_ps->out_buffer[ 1 ] ) exit( 0 );
- stereo_file_buffer = (BYTE *)malloc( buffer_byte_size * 2 );
- if( !stereo_file_buffer ) exit( 0 );
- }
- l_file_buffer = fr_ps->out_buffer[ 0 ];
- r_file_buffer = fr_ps->out_buffer[ 1 ];
- return 1;
- }
-
- static int write_file( frame_params *fr_ps )
- /*
- WARNING length is not byte length, it's sample length (8 or 16 bits)
- */
- {
- long buffer_byte_size;
- int write_length;
- register int i;
-
- if( fr_ps->out_write_length > 0 ) {
- if( fr_ps->output_8bits ) buffer_byte_size = fr_ps->out_write_length;
- else buffer_byte_size = fr_ps->out_write_length * 2;
- if( stereo_file ) {
- if( fr_ps->output_8bits ) {
- BYTE *l_sample, *r_sample, *buffer;
-
- buffer = stereo_file_buffer;
- l_sample = l_file_buffer;
- r_sample = r_file_buffer;
- for( i=0; i<fr_ps->out_write_length; i++ ) {
- *buffer++ = *l_sample++;
- *buffer++ = *r_sample++;
- }
- }
- else {
- WORD *l_sample, *r_sample, *buffer;
-
- buffer = (WORD *)stereo_file_buffer;
- l_sample = (WORD *)l_file_buffer;
- r_sample = (WORD *)r_file_buffer;
- for( i=0; i<fr_ps->out_write_length; i++ ) {
- *buffer++ = *l_sample++;
- *buffer++ = *r_sample++;
- }
- }
- write_length = fwrite( stereo_file_buffer, buffer_byte_size*2, 1, fr_ps->out_file );
- }
- else {
- write_length = fwrite( l_file_buffer, buffer_byte_size, 1, fr_ps->out_file );
- }
- if( !fr_ps->output_8bits ) write_length <<= 1;
- }
- else {
- write_length = 0;
- if ( fr_ps->out_file_type == MPEGA_FILETYPE_AIFF ) {
- IFF_AIFF pcm_aiff_data;
-
- pcm_aiff_data.numChannels = fr_ps->stereo;
- pcm_aiff_data.numSampleFrames = fr_ps->out_sample_length;
- if( fr_ps->output_8bits ) pcm_aiff_data.sampleSize = 8;
- else pcm_aiff_data.sampleSize = 16;
- pcm_aiff_data.sampleRate = fr_ps->out_sample_freq;
- pcm_aiff_data.sampleType = IFF_ID_SSND;
- pcm_aiff_data.blkAlgn.offset = 0;
- pcm_aiff_data.blkAlgn.blockSize = 0;
-
- if( AIFF_write_headers( fr_ps->out_file, &pcm_aiff_data ) == -1 ) {
- printf( "Could not write AIFF headers to \"%s\"\n", fr_ps->out_file_name );
- }
- }
- fclose( fr_ps->out_file );
- fr_ps->out_file = NULL;
- }
- fr_ps->out_buffer[ 0 ] = l_file_buffer;
- fr_ps->out_buffer[ 1 ] = r_file_buffer;
- fr_ps->out_write_length = 0;
-
- return write_length;
- }
-
- static int init_audio( frame_params *fr_ps )
- {
- BYTE flags = 0;
-
- if( fr_ps->audio_port ) return;
-
- fr_ps->out_buffer_size = fr_ps->out_sample_freq * 2; /* 2 secs buffer */
- if( fr_ps->out_buffer_size >= 0x20000L ) {
- fr_ps->out_buffer_size = 0x1FFFEL;
- }
- if( !fr_ps->output_8bits ) {
- flags |= AUF_16BITS;
- }
- if( (fr_ps->stereo > 1) && !(fr_ps->mono_forced) ) flags |= AUF_STEREO;
-
- fr_ps->audio_port = AU_open( flags, fr_ps->out_buffer_size );
-
- if( !fr_ps->audio_port ) {
- fprintf( stderr, "Can't open audio port !\n" );
- exit( 0 );
- }
- fr_ps->audio_port->frequency = fr_ps->out_sample_freq;
- fprintf( stderr, "Audio output " );
- if( flags & AUF_16BITS ) fprintf( stderr, "16-bit " );
- else fprintf( stderr, "8-bit " );
- if( flags & AUF_STEREO ) fprintf( stderr, "stereo " );
- else fprintf( stderr, "mono " );
- fprintf( stderr, "%ldHz ", fr_ps->audio_port->frequency );
-
- fr_ps->audio_port->l_vol = fr_ps->audio_port->r_vol = 64;
- fr_ps->audio_port->filter_on = fr_ps->audio_filter;
- fr_ps->audio_port->flags = AUF_FILTER | AUF_FREQ | AUF_VOL;
- fr_ps->audio_port->mixing_frequency = fr_ps->mixing_frequency;
- if( fr_ps->mixing_frequency > 0 ) {
- fr_ps->audio_port->flags |= AUF_MIXING;
- fprintf( stderr, "mixing at %ldHz\n", fr_ps->mixing_frequency );
- }
- else fprintf( stderr, "\n" );
- fr_ps->audio_port->command = AUC_CONTROL;
- AU_write( fr_ps->audio_port );
- fr_ps->out_buffer[ 0 ] = (BYTE *)fr_ps->audio_port->l_wave;
- fr_ps->out_buffer[ 1 ] = (BYTE *)fr_ps->audio_port->r_wave;
- return 1;
- }
-
- static int write_audio( frame_params *fr_ps )
- {
- int write_length = 0;
-
- if( !fr_ps->audio_port ) return 0;
- if( fr_ps->out_write_length >= 0 ) {
- fr_ps->audio_port->flags &= ~(AUF_FILTER|AUF_FREQ|AUF_VOL);
- if( fr_ps->no_audio_wait ) fr_ps->audio_port->flags |= AUF_NOWAIT;
- fr_ps->audio_port->command = AUC_WRITE;
- fr_ps->audio_port->wave_length = fr_ps->out_write_length;
- AU_write( fr_ps->audio_port );
- fr_ps->out_buffer[ 0 ] = (BYTE *)fr_ps->audio_port->l_wave;
- fr_ps->out_buffer[ 1 ] = (BYTE *)fr_ps->audio_port->r_wave;
- write_length = fr_ps->out_write_length;
- }
-
- fr_ps->out_write_length = 0;
- return write_length;
- }
-
- static int MPEGA_init_out( frame_params *fr_ps )
- {
- if( fr_ps->play ) return init_audio( fr_ps );
- else return init_file( fr_ps );
- }
-
- static void MPEGA_read_CRC( frame_params *fr_ps )
- {
- int old_crc;
-
- old_crc = BSTR_read_bits( fr_ps->bs, 16);
- }
-
- int MPEGA_seek_header( frame_params *fr_ps )
- /*------------------------------------------
- Seek, read and decode MPEG audio header
- */
- {
- if( BSTR_end( fr_ps->bs ) ) return 0;
- if( !BSTR_seek_sync( fr_ps->bs, MPEGA_SYNC_WORD, MPEGA_SYNC_WORD_LNGTH ) ) return 0;
- if( !ASM_read_header( fr_ps ) ) return 0;
- ASM_decode_header( fr_ps );
- if( fr_ps->header->error_protection ) MPEGA_read_CRC( fr_ps );
- return 1;
- }
-
- int MPEGA_init_decode( frame_params *fr_ps )
- /*------------------------------------------
- Initialize MPEG Audio decoding (analys of first frame to setup buffers)
- */
- {
- int scale_size;
-
- if( fr_ps->freq_div <= 0 ) fr_ps->freq_div = 1;
- fr_ps->sub_band_size = SBLIMIT / fr_ps->freq_div;
- ASM_init_decode( fr_ps->sub_band_size, fr_ps->output_8bits, fr_ps->quality );
-
- if( !fr_ps->bs ) {
- fr_ps->bs = BSTR_open( fr_ps->bitstream_name,
- fr_ps->bitstream_buffer_size, BSTR_MODE_READ );
- if( !fr_ps->bs ) {
- fprintf( stderr, "Can't open file '%s'\n", fr_ps->bitstream_name );
- return 0;
- }
- }
- if( !MPEGA_seek_header( fr_ps ) ) return 0;
- /* Seek to start of bitstream */
- if( !BSTR_rewind( fr_ps->bs ) ) return 0;
-
- fr_ps->out_sample_freq = fr_ps->bitstream_freq / fr_ps->freq_div;
- if( !MPEGA_init_out( fr_ps ) ) return 0; /* Initialize on first frame */
- if( fr_ps->header->lay == 1 ) scale_size = SCALE_BLOCK;
- else if ( fr_ps->header->lay == 2 ) scale_size = 3 * SCALE_BLOCK;
- else return 0;
-
- fr_ps->out_write_level = fr_ps->out_buffer_size - scale_size * fr_ps->sub_band_size;
- fr_ps->got_bits = 0;
- fr_ps->frame_count = 0;
- fr_ps->out_write_length = 0;
- fr_ps->out_sample_length = 0;
-
- return 1;
- }
-
-
-
- int MPEGA_write_out( frame_params *fr_ps )
- /*----------------------------------------
- Write out_buffer to output media
- -> return written sample count
- */
- {
- if( fr_ps->play ) return write_audio( fr_ps );
- else return write_file( fr_ps );
- }
-
- int MPEGA_decode_frame( frame_params *fr_ps )
- /*-------------------------------------------
- Decode one MPEG Audio frame
- -> return 0 if frame can't be decoded or bitstream empty
- -> return out sample length decoded otherwise
- !!! length is not in byte, but in sample count (8 or 16 bits wide)
- */
- {
- int sample_frame_length = 0;
-
- if( !MPEGA_seek_header( fr_ps ) ) return 0;
-
- switch( fr_ps->header->lay ) {
- case 1: {
- ASM_I_decode_bitalloc( fr_ps );
- ASM_I_decode_scale( fr_ps );
- if( fr_ps->mono_forced ) fr_ps->stereo = 1;
- ASM_I_decode_frame( fr_ps );
- sample_frame_length = fr_ps->sub_band_size * SCALE_BLOCK;
- break;
- }
-
- case 2: {
- ASM_II_decode_bitalloc( fr_ps );
- ASM_II_decode_scale( fr_ps );
- if( fr_ps->mono_forced ) fr_ps->stereo = 1;
- ASM_II_decode_frame( fr_ps );
- sample_frame_length = fr_ps->sub_band_size * 3 * SCALE_BLOCK;
- break;
- }
- }
- fr_ps->frame_count++;
- fr_ps->got_bits = BSTR_seek_tell( fr_ps->bs );
- fr_ps->out_write_length += sample_frame_length;
- fr_ps->out_sample_length += sample_frame_length;
-
- return sample_frame_length;
- }
-